﻿using System;
using System.Configuration;
using System.Xml.Linq;

namespace Ornament.NHibernates.Configurations
{
    /// <summary>
    /// 驱动信息
    /// </summary>
    public class DriverInfo : PropertyContainer
    {
        /// <summary>
        /// </summary>
        private DataBaseType dataBaseType;

        /// <summary>
        /// Initializes a new instance of the <see cref="DriverInfo"/> class. 
        /// </summary>
        /// <param name="sessionFactory">
        /// The session factory.
        /// </param>
        public DriverInfo(XElement sessionFactory)
            : base(sessionFactory)
        {
            ConnectionInConfig = GetPropertyValue("connection.connection_string_name") != null;
        }

        /// <summary>
        /// 驱动类型，如果更改这个驱动类型，那么<see cref="DriverClass"/>,
        /// <see cref="Dialect"/>都会一起更改。
        /// </summary>
        public DataBaseType DataBase
        {
            get { return dataBaseType ?? (dataBaseType = DataBaseType.SupportDataBaseTypes[Dialect]); }

            set
            {
                if (value == dataBaseType) return;
                DriverClass = value.SuggestionDriverClass[0];
                Dialect = value.Dialect;
                dataBaseType = value;
            }
        }

        /// <summary>
        /// gets or sets ConnectionString.Driver_class 
        /// it should be in <see cref="DataBaseType.SuggestionDriverClass"/>
        /// </summary>
        public string DriverClass
        {
            get { return GetPropertyValue("connection.driver_class"); }

            set
            {
                bool found = false;
                foreach (string driverCls in DataBase.SuggestionDriverClass)
                {
                    if (driverCls == value)
                    {
                        found = true;
                        break;
                    }
                }

                if (found)
                {
                    SetPropertyValue("connection.driver_class", value);
                }
                else
                {
                    throw new ArgumentOutOfRangeException(
                        value + " should be one of " + String.Join(",", DataBase.SuggestionDriverClass));
                }
            }
        }

        /// <summary>
        /// Gets Dialect
        /// </summary>
        public string Dialect
        {
            get { return GetPropertyValue("dialect"); }
            private set { SetPropertyValue("dialect", value); }
        }

        public bool ConnectionInConfig { get; private set; }

        public string ConnectionStringKey
        {
            get { return ConnectionInConfig ? GetPropertyValue("connection.connection_string_name") : ""; }
            set
            {
                if (ConnectionInConfig)
                {
                    SetPropertyValue("connection.connection_string_name", value);
                }
                else
                {
                    RemoveProperty("connection.connection_string_name");
                }
            }
        }

        /// <summary>
        /// Gets or sets ConnectionString.
        /// </summary>
        /// <value>
        /// The connection string.
        /// </value>
        public string ConnectionString
        {
            get
            {
                if (ConnectionInConfig)
                {
                    return ConfigurationManager.ConnectionStrings[ConnectionStringKey].ConnectionString;
                }
                else
                {
                    return GetPropertyValue("connection.connection_string");
                }
            }

            set
            {
                if (ConnectionInConfig)
                {
                    ConfigurationManager.ConnectionStrings[ConnectionStringKey].ConnectionString = value;
                }
                else
                {
                    SetPropertyValue("connection.connection_string", value);
                }
            }
        }

        /// <summary>
        /// Changes the connection info.
        /// </summary>
        /// <param name="useConfigFile">if set to <c>true</c> [use config file].</param>
        /// <param name="connectionStringKey">The connection string key.</param>
        public void ChangeConnectionInfo(bool useConfigFile, string connectionStringKey)
        {
            string srcConnStri = ConnectionString;
            if (useConfigFile)
            {
                if (ConfigurationManager.ConnectionStrings[connectionStringKey] != null)
                {
                    ConfigurationManager.ConnectionStrings[connectionStringKey].ConnectionString = srcConnStri;
                }
                else
                {
                    ConfigurationManager.ConnectionStrings.Add(new ConnectionStringSettings(connectionStringKey,
                                                                                            srcConnStri));
                }

                if (ConnectionStringKey != connectionStringKey && ConnectionInConfig)
                {
                    DeleteConnectionInfo(ConnectionStringKey);
                    ConnectionStringKey = connectionStringKey;
                }
                Delete("connection.connection_string");
                ConnectionInConfig = useConfigFile;
            }
            else
            {
                if (ConnectionInConfig)
                {
                    DeleteConnectionInfo(ConnectionStringKey);
                }
                ConnectionInConfig = useConfigFile;
                ConnectionString = srcConnStri;
            }
        }

        private void DeleteConnectionInfo(string connectionStringKey)
        {
            var a = new ConnectionStringSettings();
            a.Name = connectionStringKey;
            ConfigurationManager.ConnectionStrings.Remove(a);
        }
    }
}